﻿using System;
using System.Text;
using MultiLang;

namespace Rsdn.Janus
{
    /// <summary>
    ///   A set of C# classes for spelling Russian numeric's 
    ///   Copyright (c) 2002 Rsdn Group
    /// </summary>
    public static class RusNumber
    {
        private static readonly string[] _frac20Male =
            new[]
                {
                    string.Empty, 
                    ml.ml_string(58, "один"), 
                    ml.ml_string(59, "два"), 
                    ml.ml_string(141, "три"), 
                    ml.ml_string(142, "четыре"), 
                    ml.ml_string(143, "пять"), 
                    ml.ml_string(144, "шесть"), 
                    ml.ml_string(145, "семь"), 
                    ml.ml_string(146, "восемь"), 
                    ml.ml_string(147, "девять"), 
                    ml.ml_string(148, "десять"), 
                    ml.ml_string(149, "одиннадцать"), 
                    ml.ml_string(150, "двенадцать"),
                    ml.ml_string(151, "тринадцать"), 
                    ml.ml_string(152, "четырнадцать"), 
                    ml.ml_string(153, "пятнадцать"), 
                    ml.ml_string(154, "шестнадцать"), 
                    ml.ml_string(155, "семнадцать"), 
                    ml.ml_string(156, "восемнадцать"), 
                    ml.ml_string(157, "девятнадцать")
                };

        private static readonly string[] _frac20Female =
            new[]
                {
                    string.Empty,
                    ml.ml_string(77, "одна"), 
                    ml.ml_string(78, "две"), 
                    ml.ml_string(60, "три"), 
                    ml.ml_string(61, "четыре"), 
                    ml.ml_string(62, "пять"), 
                    ml.ml_string(63, "шесть"), 
                    ml.ml_string(64, "семь"), 
                    ml.ml_string(65, "восемь"), 
                    ml.ml_string(66, "девять"), 
                    ml.ml_string(158, "десять"), 
                    ml.ml_string(68, "одиннадцать"), 
                    ml.ml_string(69, "двенадцать"), 
                    ml.ml_string(70, "тринадцать"), 
                    ml.ml_string(71, "четырнадцать"), 
                    ml.ml_string(72, "пятнадцать"), 
                    ml.ml_string(73, "шестнадцать"), 
                    ml.ml_string(74, "семнадцать"), 
                    ml.ml_string(75, "восемнадцать"), 
                    ml.ml_string(76, "девятнадцать")
                };

        private static readonly string[] _hunds =
            {
                string.Empty, ml.ml_string(116, "сто"), ml.ml_string(115, "двести"), ml.ml_string(114, "триста"), 
                ml.ml_string(113, "четыреста"), 
                ml.ml_string(112, "пятьсот"), ml.ml_string(111, "шестьсот"), ml.ml_string(110, "семьсот"), 
                ml.ml_string(109, "восемьсот"), ml.ml_string(108, "девятьсот")
            };

        private static readonly string[] _tens =
            {
                string.Empty, ml.ml_string(67, "десять"), ml.ml_string(107, "двадцать"), ml.ml_string(106, "тридцать"), 
                ml.ml_string(105, "сорок"), ml.ml_string(104, "пятьдесят"), 
                ml.ml_string(103, "шестьдесят"), ml.ml_string(102, "семьдесят"), ml.ml_string(101, "восемьдесят"), 
                ml.ml_string(100, "девяносто")
            };


        public static string ToRubles(this decimal value)
        {
            decimal rubVal = Math.Truncate(value);
            decimal kopVal = (value - rubVal)*100;
            var rubResult = rubVal.RusSpelledOut(
                true, ml.ml_string(99, "рубль"), ml.ml_string(98, "рубля"), ml.ml_string(97, "рублей"));
            rubResult = rubResult.Length >= 1 ? char.ToUpper(rubResult[0]) + rubResult.Substring(1) : rubResult;
            if (kopVal > 0)
            {
                var kopResult = kopVal.RusSpelledOut(
                    false, ml.ml_string(96, "копейка"), ml.ml_string(95, "копейки"), ml.ml_string(94, "копеек"));
                return rubResult + " " + kopResult; // MLHIDE
            }

            return rubResult;
        }

        public static string RusSpelledOut(
            this decimal value, 
            bool male)
        {
            if (value >= 1000000000000000)
            {
                throw new ArgumentOutOfRangeException("value");       //MLHIDE
            }

            StringBuilder str = new StringBuilder();

            if (value < 0)
            {
                str.Append(ml.ml_string(92, "минус"));
                value = -value;
            }

            value = value
                .AppendPeriod(
                    1000000000000, 
                    str, 
                    ml.ml_string(91, "триллион"), 
                    ml.ml_string(90, "триллиона"), 
                    ml.ml_string(89, "триллионов"), 
                    true)
                .AppendPeriod(
                    1000000000, 
                    str, 
                    ml.ml_string(88, "миллиард"), 
                    ml.ml_string(87, "миллиарда"), 
                    ml.ml_string(86, "миллиардов"), 
                    true)
                .AppendPeriod(
                    1000000, 
                    str, 
                    ml.ml_string(85, "миллион"), 
                    ml.ml_string(84, "миллиона"), 
                    ml.ml_string(83, "миллионов"), 
                    true)
                .AppendPeriod(
                    1000, str, ml.ml_string(82, "тысяча"), ml.ml_string(81, "тысячи"), ml.ml_string(80, "тысяч"), false);

            int hundreds = (int) (value/100);
            if (hundreds != 0)
            {
                str.AppendWithSpace(_hunds[hundreds]);
            }

            int less100 = (int) (value % 100);
            string[] frac20 = male ? _frac20Male : _frac20Female;
            if (less100 < 20)
            {
                str.AppendWithSpace(frac20[less100]);
            }
            else
            {
                int tens = less100/10;
                str.AppendWithSpace(_tens[tens]);
                int less10 = less100%10;
                if (less10 != 0)
                {
                    str.Append(" " + frac20[less100%10]); // MLHIDE
                }
            }

            return str.ToString();
        }

        private static void AppendWithSpace(this StringBuilder stringBuilder, string str)
        {
            if (stringBuilder.Length > 0)
            {
                stringBuilder.Append(" "); // MLHIDE
            }

            stringBuilder.Append(str);
        }

        private static decimal AppendPeriod(
            this decimal value, 
            long power, 
            StringBuilder str, 
            string declension1, 
            string declension2, 
            string declension5, 
            bool male)
        {
            int thousands = (int) (value/power);
            if (thousands > 0)
            {
                str.AppendWithSpace(
                    ((decimal) thousands).RusSpelledOut(male, declension1, declension2, declension5));
                return value%power;
            }

            return value;
        }

        public static string RusSpelledOut(
            this decimal value, 
            bool male, 
            string valueDeclensionFor1, 
            string valueDeclensionFor2, 
            string valueDeclensionFor5)
        {
            return
                RusSpelledOut(value, male)
                + " " // MLHIDE
                + ((int) (value%10)).GetDeclension(valueDeclensionFor1, valueDeclensionFor2, valueDeclensionFor5);
        }
    }
}